package dao

import (
	"fmt"
	"sort"
	"time"

	"gorm.io/gorm"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/internal/global"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/internal/module/common/enum/script"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/internal/module/common/enum/workflow"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/internal/module/job_workflow/model"
	scriptlibrary "openeuler.org/PilotGo/PilotGo-plugin-automation/internal/module/script_library/dao"
	tag "openeuler.org/PilotGo/PilotGo-plugin-automation/internal/module/script_library/model"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/pkg/response"
	"openeuler.org/PilotGo/PilotGo-plugin-automation/pkg/utils"
)

func CreateWorkflow(dto *model.TaskWorkflowDTO) error {
	return global.App.MySQL.Transaction(func(tx *gorm.DB) error {
		// 1. 插入模板
		workflow := &model.TaskWorkflow{
			Name:          dto.Workflow.Name,
			Description:   dto.Workflow.Description,
			Tag:           dto.Workflow.Tag,
			OperationType: dto.Workflow.OperationType,
			PublishStatus: dto.Workflow.PublishStatus,
			UsageType:     dto.Workflow.UsageType,
			ModifyUser:    dto.Workflow.ModifyUser,
			ModifyTime:    time.Now().Format("2006-01-02 15:04:05"),
		}
		if err := tx.Create(workflow).Error; err != nil {
			return err
		}
		workflowId := workflow.ID

		// 2. 插入输入参数
		if len(dto.Params) > 0 {
			for i := range dto.Params {
				dto.Params[i].WorkflowId = workflowId
			}
			if err := tx.Create(&dto.Params).Error; err != nil {
				return err
			}
		}
		// 3. 插入输出参数
		if len(dto.OutputParams) > 0 {
			for i := range dto.OutputParams {
				dto.OutputParams[i].WorkflowId = workflowId
			}
			if err := tx.Create(&dto.OutputParams).Error; err != nil {
				return err
			}
		}

		// 4. 插入步骤 & 脚本
		if len(dto.Steps) > 0 {
			// 4.1 按 stepNum 排序，补全链路
			sort.Slice(dto.Steps, func(i, j int) bool {
				return dto.Steps[i].StepNum < dto.Steps[j].StepNum
			})

			for i := range dto.Steps {
				dto.Steps[i].WorkflowId = workflowId
				if i > 0 {
					dto.Steps[i].PreviousStepNum = dto.Steps[i-1].StepNum
				}
				if i < len(dto.Steps)-1 {
					dto.Steps[i].NextStepNum = dto.Steps[i+1].StepNum
				}
			}

			if err := tx.Create(&dto.Steps).Error; err != nil {
				return err
			}

			// 4.2 设置模板的首尾步骤
			workflow.FirstStepNum = dto.Steps[0].StepNum
			workflow.LastStepNum = dto.Steps[len(dto.Steps)-1].StepNum
			// 4.3 回写模板首尾步骤
			if err := tx.Model(&model.TaskWorkflow{}).
				Where("id = ?", workflowId).
				Updates(map[string]interface{}{
					"first_step_num": workflow.FirstStepNum,
					"last_step_num":  workflow.LastStepNum,
				}).Error; err != nil {
				return err
			}
		}

		if len(dto.Scripts) > 0 {
			for i, script := range dto.Scripts {
				scriptVersionId, scriptPublishedVersion, content, _ := scriptlibrary.GetPublishedScriptContentByScriptId(script.ScriptId)
				dto.Scripts[i].WorkflowId = workflowId
				dto.Scripts[i].ScriptContent = content
				dto.Scripts[i].ScriptVersionId = scriptVersionId
				dto.Scripts[i].ScriptPublishedVersion = scriptPublishedVersion
			}
			if err := tx.Create(&dto.Scripts).Error; err != nil {
				return err
			}
		}

		return nil
	})
}

func DeleteWorkflow(ids []int) error {
	return global.App.MySQL.Transaction(func(tx *gorm.DB) error {
		// 1. 删除脚本表数据
		if err := tx.Where("workflow_id IN ?", ids).Unscoped().Delete(&model.TaskWorkflowStepScript{}).Error; err != nil {
			return err
		}

		// 2. 删除步骤表数据
		if err := tx.Where("workflow_id IN ?", ids).Unscoped().Delete(&model.TaskWorkflowStep{}).Error; err != nil {
			return err
		}

		// 3. 删除输出参数表数据
		if err := tx.Where("workflow_id IN ?", ids).Unscoped().Delete(&model.TaskWorkflowOutputParams{}).Error; err != nil {
			return err
		}

		// 4. 删除输入参数表数据
		if err := tx.Where("workflow_id IN ?", ids).Unscoped().Delete(&model.TaskWorkflowParams{}).Error; err != nil {
			return err
		}

		// 5. 最后删除模板表数据
		if err := tx.Where("id IN ?", ids).Unscoped().Delete(&model.TaskWorkflow{}).Error; err != nil {
			return err
		}

		return nil
	})
}

func UpdateWorkflow(dto *model.TaskWorkflowDTO) error {
	return global.App.MySQL.Transaction(func(tx *gorm.DB) error {
		workflowId := dto.Workflow.ID
		// 1. 更新模板基本信息
		workflow := &model.TaskWorkflow{
			Name:          dto.Workflow.Name,
			Description:   dto.Workflow.Description,
			OperationType: dto.Workflow.OperationType,
			Tag:           dto.Workflow.Tag,
			ModifyUser:    dto.Workflow.ModifyUser,
			ModifyTime:    time.Now().Format("2006-01-02 15:04:05"),
		}
		if err := tx.Model(&model.TaskWorkflow{}).Where("id = ?", workflowId).Updates(workflow).Error; err != nil {
			return err
		}

		// 2. 删除旧的输入参数，插入新的输入参数
		if err := tx.Where("workflow_id = ?", workflowId).Delete(&model.TaskWorkflowParams{}).Error; err != nil {
			return err
		}
		if len(dto.Params) > 0 {
			for i := range dto.Params {
				dto.Params[i].WorkflowId = workflowId
			}
			if err := tx.Create(&dto.Params).Error; err != nil {
				return err
			}
		}
		// 3. 删除旧的输出参数，插入新的输出参数
		if err := tx.Where("workflow_id = ?", workflowId).Delete(&model.TaskWorkflowOutputParams{}).Error; err != nil {
			return err
		}
		if len(dto.OutputParams) > 0 {
			for i := range dto.OutputParams {
				dto.OutputParams[i].WorkflowId = workflowId
			}
			if err := tx.Create(&dto.OutputParams).Error; err != nil {
				return err
			}
		}

		// 4. 删除旧的步骤，插入新的步骤 & 脚本
		if err := tx.Where("workflow_id = ?", workflowId).Delete(&model.TaskWorkflowStep{}).Error; err != nil {
			return err
		}
		if len(dto.Steps) > 0 {
			// 4.1 按 stepNum 排序，补全链路
			sort.Slice(dto.Steps, func(i, j int) bool {
				return dto.Steps[i].StepNum < dto.Steps[j].StepNum
			})

			for i := range dto.Steps {
				dto.Steps[i].WorkflowId = workflowId
				if i > 0 {
					dto.Steps[i].PreviousStepNum = dto.Steps[i-1].StepNum
				}
				if i < len(dto.Steps)-1 {
					dto.Steps[i].NextStepNum = dto.Steps[i+1].StepNum
				}
			}

			if err := tx.Create(&dto.Steps).Error; err != nil {
				return err
			}

			// 4.2 设置编排的首尾步骤
			workflow.FirstStepNum = dto.Steps[0].StepNum
			workflow.LastStepNum = dto.Steps[len(dto.Steps)-1].StepNum
			// 4.3 回写编排首尾步骤
			if err := tx.Model(&model.TaskWorkflow{}).
				Where("id = ?", workflowId).
				Updates(map[string]interface{}{
					"first_step_num": workflow.FirstStepNum,
					"last_step_num":  workflow.LastStepNum,
				}).Error; err != nil {
				return err
			}
		}
		// 5. 删除旧的脚本，插入新的脚本
		if err := tx.Where("workflow_id = ?", workflowId).Delete(&model.TaskWorkflowStepScript{}).Error; err != nil {
			return err
		}

		if len(dto.Scripts) > 0 {
			for i, script := range dto.Scripts {
				scriptVersionId, scriptPublishedVersion, content, _ := scriptlibrary.GetPublishedScriptContentByScriptId(script.ScriptId)
				dto.Scripts[i].WorkflowId = workflowId
				dto.Scripts[i].ScriptContent = content
				dto.Scripts[i].ScriptVersionId = scriptVersionId
				dto.Scripts[i].ScriptPublishedVersion = scriptPublishedVersion
			}
			if err := tx.Create(&dto.Scripts).Error; err != nil {
				return err
			}
		}

		return nil
	})
}

func QueryWorkflows(query *response.PagedQuery, publishStatus, tag string) ([]model.TaskWorkflow, int, error) {
	var total int64
	var workflows []model.TaskWorkflow
	q := global.App.MySQL.Model(&model.TaskWorkflow{})
	qc := global.App.MySQL.Model(&model.TaskWorkflow{})

	if query.Search != "" {
		if utils.IsDsl(query.Search) {
			q = q.Where(query.Search)
			qc = qc.Where(query.Search)
		} else {
			searchValue := query.Search
			q = q.Where("name LIKE ? OR tag LIKE ? OR publish_status LIKE ? OR usage_type LIKE ?",
				"%"+searchValue+"%", "%"+searchValue+"%", fmt.Sprintf("%%%d%%", workflow.ParsePublishStatus(searchValue)), "%"+searchValue+"%")
			qc = qc.Where("name LIKE ? OR tag LIKE ? OR publish_status LIKE ? OR usage_type LIKE ?",
				"%"+searchValue+"%", "%"+searchValue+"%", fmt.Sprintf("%%%d%%", workflow.ParsePublishStatus(searchValue)), "%"+searchValue+"%")
		}
	}

	if len(publishStatus) != 0 {
		q = q.Where("publish_status = ?", workflow.ParsePublishStatus(publishStatus))
		qc = qc.Where("publish_status = ?", workflow.ParsePublishStatus(publishStatus))
	}

	if len(tag) != 0 {
		q = q.Where("tag = ?", tag)
		qc = qc.Where("tag = ?", tag)
	}

	if err := q.Limit(query.PageSize).Offset((query.CurrentPage - 1) * query.PageSize).Order("id desc").Find(&workflows).Error; err != nil {
		return nil, 0, err
	}

	if err := qc.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	return workflows, int(total), nil
}
func GetWorkflows() ([]model.TaskWorkflow, error) {
	var workflows []model.TaskWorkflow
	if err := global.App.MySQL.Model(&model.TaskWorkflow{}).Find(&workflows).Error; err != nil {
		return []model.TaskWorkflow{}, err
	}
	return workflows, nil
}

func GetWorkflowById(id string) (interface{}, error) {
	var workflow model.TaskWorkflow
	// 1. 查询编排基本信息
	if err := global.App.MySQL.Model(&model.TaskWorkflow{}).Where("id = ?", id).First(&workflow).Error; err != nil {
		return nil, err
	}
	// 2. 查询变量
	var params []model.TaskWorkflowParams
	if err := global.App.MySQL.Model(&model.TaskWorkflowParams{}).Where("workflow_id = ?", id).Find(&params).Error; err != nil {
		return nil, err
	}
	var output_params []model.TaskWorkflowOutputParams
	if err := global.App.MySQL.Model(&model.TaskWorkflowOutputParams{}).Where("workflow_id = ?", id).Find(&output_params).Error; err != nil {
		return nil, err
	}
	// 3. 查询步骤
	var steps []model.TaskWorkflowStep
	if err := global.App.MySQL.Model(&model.TaskWorkflowStep{}).Where("workflow_id = ?", id).Find(&steps).Error; err != nil {
		return nil, err
	}
	// 4. 查询脚本
	var scripts []model.TaskWorkflowStepScript
	if err := global.App.MySQL.Model(&model.TaskWorkflowStepScript{}).Where("workflow_id = ?", id).Find(&scripts).Error; err != nil {
		return nil, err
	}
	var data = map[string]interface{}{}
	data["id"] = workflow.ID
	data["name"] = workflow.Name
	data["description"] = workflow.Description
	data["tag"] = workflow.Tag
	data["publish_status"] = workflow.PublishStatus
	data["operation_type"] = workflow.OperationType
	data["usage_type"] = workflow.UsageType
	data["modify_user"] = workflow.ModifyUser
	data["modify_time"] = workflow.ModifyTime
	data["params"] = params
	data["output_params"] = output_params
	data["steps"] = steps
	data["scripts"] = scripts
	return data, nil
}

func GetWorkflowStepScriptById(id string) ([]model.WorkflowStepDetail, error) {
	var result []model.WorkflowStepDetail

	err := global.App.MySQL.Table("task_workflow_step AS step").
		Select(`
            step.step_num,
            step.step_type,
            script.script_type,
            script.script_id,
            script.script_version_id,
            script.script_content,
            script.script_param,
            script.script_timeout
        `).
		Joins("LEFT JOIN task_workflow_step_script AS script ON step.workflow_id = script.workflow_id AND step.step_num = script.step_num").
		Where("step.workflow_id = ?", id).
		Order("step.step_num ASC").
		Find(&result).Error

	if err != nil {
		return nil, err
	}

	return result, nil
}

func GetTagEnNameByWorkflowId(id int) (string, string, error) {
	var wf model.TaskWorkflow
	err := global.App.MySQL.Model(&model.TaskWorkflow{}).Where("id = ?", id).First(&wf).Error
	if err != nil {
		return "", "", err
	}

	var t tag.Tag
	err = global.App.MySQL.Model(&tag.Tag{}).Where("name = ?", wf.Tag).First(&t).Error
	if err != nil {
		return wf.Name, "", err
	}
	return wf.Name, t.EnName, nil
}

func PublishWorkflow(id int, newStatus string) error {
	return global.App.MySQL.Transaction(func(tx *gorm.DB) error {
		if err := tx.Model(&model.TaskWorkflow{}).Where("id = ?", id).Update("publish_status", script.ParseScriptPublishStatus(newStatus)).Error; err != nil {
			return err
		}
		return nil
	})
}

func NotifyRelatedTaskWorkflowToSync(scriptId string) error {
	var workflowIDs []int
	if err := global.App.MySQL.Model(&model.TaskWorkflowStepScript{}).
		Where("script_id = ?", scriptId).
		Pluck("workflow_id", &workflowIDs).Error; err != nil {
		return err
	}

	if len(workflowIDs) == 0 {
		return nil
	}

	if err := global.App.MySQL.Model(&model.TaskWorkflow{}).
		Where("id IN ?", workflowIDs).
		Update("to_sync", true).Error; err != nil {
		return err
	}

	if err := global.App.MySQL.Model(&model.TaskWorkflowStepScript{}).
		Where("workflow_id IN ? AND script_id = ?", workflowIDs, scriptId).
		Update("to_sync", true).Error; err != nil {
		return err
	}
	return nil
}

func RelatedTaskWorkflowToSync(workflowId string) error {
	var steps []model.TaskWorkflowStepScript
	if err := global.App.MySQL.
		Where("workflow_id = ? AND to_sync = ?", workflowId, true).
		Find(&steps).Error; err != nil {
		return fmt.Errorf("查询待同步步骤失败: %w", err)
	}

	if len(steps) == 0 {
		return nil
	}

	for _, step := range steps {
		versionID, scriptPublishedVersion, content, err := scriptlibrary.GetPublishedScriptContentByScriptId(step.ScriptId)
		if err != nil {
			return fmt.Errorf("获取脚本最新版本失败, script_id: %s, err=%v", step.ScriptId, err)
		}

		updateData := map[string]interface{}{
			"script_version_id":        versionID,
			"script_content":           content,
			"script_published_version": scriptPublishedVersion,
			"to_sync":                  false,
		}

		if err := global.App.MySQL.Model(&model.TaskWorkflowStepScript{}).
			Where("workflow_id = ? AND script_id = ?", workflowId, step.ScriptId).
			Updates(updateData).Error; err != nil {
			return fmt.Errorf("更新步骤 %d 失败: %w", step.ID, err)
		}
	}

	if err := global.App.MySQL.Model(&model.TaskWorkflow{}).
		Where("id = ?", workflowId).
		Update("to_sync", false).Error; err != nil {
		return err
	}
	return nil
}
